package ro.isdc.vms.utils.hibernate.interceptor;

import java.io.Serializable;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.dao.OptimisticLockingFailureException;

import ro.isdc.vms.utils.timestamp.TimeStampUtil;

/**
 * Audit interceptor. It audits operations on entities such as save and update and
 * it automatically sets correct data for creationTimeStamp and lastUpdateTimeStamp.
 * @author Andrei Chirila / ISDC! Romania
 * @version 1.0.0
 * @date Jul 22, 2009
 */
public class AuditInterceptor extends EmptyInterceptor {

  /**
   * Generated serial version UID.
   */
  private static final long serialVersionUID = 1946079371810536072L;

  public boolean onFlushDirty(final Object entity, final Serializable id,
      final Object[] currentState, final Object[] previousState, 
      final String[] propertyNames, final Type[] types) {
    
    boolean modified = false;
    for (int i = 0; i < propertyNames.length; i++) {
      if ("lastUpdateTimestamp".equalsIgnoreCase(propertyNames[i])) {
        currentState[i] = TimeStampUtil.getTimeStamp();
        modified = true;
      }
      
//      if ("lastUpdatedBy".equalsIgnoreCase(propertyNames[i])) {
//        currentState[i] = BusinessContextThreadLocal.get().getSystemUserId();
//        modified = true;
//      }

      if (previousState != null) {
        /* 
         * only check version numbers when a previos state exists (i.i. 
         * on update)
         */
        if ("versionNo".equalsIgnoreCase(propertyNames[i])) {
          if ((Integer) currentState[i] < (Integer) previousState[i]) {
            throw new OptimisticLockingFailureException(
                "Concurrency problem occured. Old version number " 
                + previousState[i] + " does not match the new version number " 
                + currentState[i] + " (entity type: " 
                + entity.getClass().getName() + ")");
          }
        }
      }
    }
    
    return modified || super.onFlushDirty(entity, id, currentState, previousState,
        propertyNames, types);
  }

  public boolean onSave(final Object entity, final Serializable id, 
      final Object[] state, final String[] propertyNames, final Type[] types) {
    
    boolean modified = false;
    for (int i = 0; i < propertyNames.length; i++) {
      if ("creationTimestamp".equalsIgnoreCase(propertyNames[i])) {
        state[i] = TimeStampUtil.getTimeStamp();
        modified = true;
      }
      
//      if ("createdBy".equalsIgnoreCase(propertyNames[i])) {
//        state[i] = BusinessContextThreadLocal.get().getSystemUserId();;
//        modified = true;
//      }
      
      if ("lastUpdateTimestamp".equalsIgnoreCase(propertyNames[i])) {
        state[i] = TimeStampUtil.getTimeStamp();
        modified = true;
      }
      
//      if ("lastUpdatedBy".equalsIgnoreCase(propertyNames[i])) {
//        state[i] = BusinessContextThreadLocal.get().getSystemUserId();
//        modified = true;
//      }
    }

    return modified || super.onSave(entity, id, state, propertyNames, types);
  }
}